<?php

/**
 * This file is part of Rangine
 *
 * (c) We7Team 2019 <https://www.rangine.com/>
 *
 * document http://s.w7.cc/index.php?c=wiki&do=view&id=317&list=2284
 *
 * visited https://www.rangine.com/ for more details
 */

namespace W7\Core\Database\Command\Migrate;

use Symfony\Component\Console\Input\InputOption;
use W7\Console\Command\CommandAbstract;
use W7\Console\Command\ConfirmTrait;

class RefreshCommand extends CommandAbstract {
	use ConfirmTrait;

	/**
	 * The console command description.
	 *
	 * @var string
	 */
	protected $description = 'reset and re-run all migrations';

	protected function configure() {
		$this->addOption('--database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use', 'default');
		$this->addOption('--force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production');
		$this->addOption('--path', null, InputOption::VALUE_OPTIONAL, 'The path to the migrations files to be executed');
		$this->addOption('--realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths');
		$this->addOption('--seed', null, InputOption::VALUE_NONE, 'Indicates if the seed task should be re-run');
		$this->addOption('--seeder', null, InputOption::VALUE_OPTIONAL, 'The class name of the root seeder');
		$this->addOption('--step', null, InputOption::VALUE_OPTIONAL, 'Force the migrations to be run so they can be rolled back individually');
	}

	/**
	 * Execute the console command.
	 *
	 * @return void
	 */
	protected function handle($options) {
		if (! $this->confirmToProceed()) {
			return;
		}

		// Next we'll gather some of the options so that we can have the right options
		// to pass to the commands. This includes options such as which database to
		// use and the path to use for the migration. Then we'll run the command.
		$database = $this->input->getOption('database');

		$path = $this->input->getOption('path');

		// If the "step" option is specified it means we only want to rollback a small
		// number of migrations before migrating again. For example, the user might
		// only rollback and remigrate the latest four migrations instead of all.
		$step = $this->input->getOption('step') ?: 0;

		if ($step > 0) {
			$this->runRollback($database, $path, $step);
		} else {
			$this->runReset($database, $path);
		}

		// The refresh command is essentially just a brief aggregate of a few other of
		// the migration commands and just provides a convenient wrapper to execute
		// them in succession. We'll also see if we need to re-seed the database.
		$this->call('migrate:migrate', array_filter([
			'--database' => $database,
			'--path' => $path,
			'--realpath' => $this->input->getOption('realpath'),
			'--force' => true,
		]));

		if ($this->needsSeeding()) {
			$this->runSeeder($database);
		}
	}

	/**
	 * Run the rollback command.
	 *
	 * @param  string  $database
	 * @param  string  $path
	 * @param  int  $step
	 * @return void
	 */
	protected function runRollback($database, $path, $step) {
		$this->call('migrate:rollback', array_filter([
			'--database' => $database,
			'--path' => $path,
			'--realpath' => $this->input->getOption('realpath'),
			'--step' => $step,
			'--force' => true,
		]));
	}

	/**
	 * Run the reset command.
	 *
	 * @param  string  $database
	 * @param  string  $path
	 * @return void
	 */
	protected function runReset($database, $path) {
		$this->call('migrate:reset', array_filter([
			'--database' => $database,
			'--path' => $path,
			'--realpath' => $this->input->getOption('realpath'),
			'--force' => true,
		]));
	}

	/**
	 * Determine if the developer has requested database seeding.
	 *
	 * @return bool
	 */
	protected function needsSeeding() {
		return $this->option('seed') || $this->option('seeder');
	}

	/**
	 * Run the database seeder command.
	 *
	 * @param  string  $database
	 * @return void
	 */
	protected function runSeeder($database) {
		$this->call('seed:seed', array_filter([
			'--database' => $database,
			'--class' => $this->option('seeder') ?: 'DatabaseSeeder',
			'--force' => true,
		]));
	}
}
